import Reflect from "@/utils/reflect";

type RequestMethod<P, R> = (this: any, params: P) => Promise<R>;

interface CheckValue<P> {
  params: P[];
  promise: { reslove: Function, reject: Function };
}

/** 合并接口返回 */
export function ResponseMerge<P, R>(getKey: (item: R) => P, timeout?: number) {

  return function (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<RequestMethod<P[], R[]>>) {
    Reflect.setValue(target, ["ResponseMerge", propertyKey], descriptor.value);

    descriptor.value = function() {
      let timeId: undefined | number | NodeJS.Timeout = undefined;
      let saveList: CheckValue<P>[] = null as unknown as CheckValue<P>[];

      return async function (params) {
        // 构建异步对象
        let reslove: Function = () => {};
        let reject: Function = () => {};
        const promise = new Promise<R[]>((loc_reslove, loc_reject) => {
          reslove = loc_reslove;
          reject = loc_reject;
        });
        // 储存参数
        if (saveList === null) {
          saveList = [];
        }
        saveList.push({ params, promise: { reslove, reject } });
        // 清理定时器
        if (timeId) {
          clearTimeout(timeId);
          timeId = undefined;
        }

        // 进行异步请求
        timeId = setTimeout(async () => {
          // 构建请求数据
          const promiseEntries = [...saveList];
          const params = Array.from(new Set(promiseEntries.map(item => item.params).flat()));
          // 清空缓存
          saveList = null as unknown as CheckValue<P>[];
          timeId = undefined;
          try {
            // 请求数据
            const results: R[] = await Reflect.getValue<RequestMethod<P[], R[]>>(target, ["ResponseMerge", propertyKey]).call(this, params);
            // 构建请求表
            const resultMap = Object.fromEntries(results.map(item => [getKey(item), item]));
            // 返回请求成功数据
            for (const item of promiseEntries) {
              const values = [];
              for (const param of item.params) {
                if (resultMap[param]) {
                  values.push(resultMap[param]);
                }
              }
              item.promise.reslove(values);
            }
          } catch (error) {
            // 触发请求失败
            for (const item of promiseEntries) {
              item.promise.reject(error);
            }
          }
        }, timeout);
        // 返回异步对象
        return promise;
      };
    }();

  };

}
